/**
* Oxide
*
* Copyright (c) 2011 Dinosaur Kick Pty Ltd, All rights reserved.
*
* This source code is made available under the "Modified BSD" licensing arrangement.
* See license.txt for details.
*/
// ----------------------------------------------------------------------------
#include <string>
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include "oxide-common/ast/ast_fwd.hpp"
#include "oxide-common/renderer/cstyle_renderer.hpp"
// ----------------------------------------------------------------------------
#ifndef O2_CODEGEN_PHP_PHP_VISITOR
#define O2_CODEGEN_PHP_PHP_VISITOR
namespace o2 {
namespace codegen {
namespace php {
// ----------------------------------------------------------------------------

template <typename StringT>
class basic_php_renderer
	: public o2::renderer::basic_cstyle_renderer<basic_php_renderer<StringT>, StringT>
{
	public:
		typedef StringT string_type;
		O2_AST_TYPEDEFS(StringT);

	public:
		string_type visit(const root_type& node)
		{
			string_type result = O2_CSTR("<?php\n");
			if (node.class_)
			{
				result += O2_CSTR("namespace ");
				result += boost::algorithm::join(node.class_->namespace_atoms, O2_CSTR("\\"));
				result += O2_CSTR(";\n");
				result += visit(*node.class_);
			}
			return result;
		}
		
		string_type visit(const class_decl_type& node)
		{
			string_type result;
			if (node.is_final)
				result += O2_CSTR("final ");
			else if (node.is_abstract)
				result += O2_CSTR("abstract ");
			result += O2_CSTR("class ");
			result += node.name;
			result += O2_CSTR("\n");
			result += this->open_block('{');
			result += O2_CSTR("\n");
			BOOST_FOREACH(const typename class_member_map::value_type& pair, node.members)
				result += this->apply(*pair.second) + O2_CSTR("\n");
			result += this->close_block();
			return result;
		}
		
		string_type visit(const method_type& node)
		{
			string_type result = this->indent() + node.access + O2_CSTR(" ");
			if (node.is_static)
				result += O2_CSTR("static ");
			if (node.is_final)
				result += O2_CSTR("final ");
			result += O2_CSTR("function ");
			result += method_name(node.name);
			result += O2_CSTR("() //") + this->apply(*node.type) + O2_CSTR("\n");
			if (node.stmt_block)
				result += O2_CSTR("\n") + this->apply(*node.stmt_block);
			else
				result += O2_CSTR(";\n");
			return result;
		}

		string_type visit(const member_var_type& node)
		{
			string_type result = this->indent() + node.access + O2_CSTR(" ");
			if (node.is_static)
				result += O2_CSTR("static ");
			result += node.name;
			if (node.default_value)
				result += O2_CSTR(" = ") + this->apply(*node.default_value);
			result += O2_CSTR("; //") + this->apply(*node.type) + O2_CSTR("\n");
			return result;
		}
		
		string_type visit(const stmt_block_type& node)
		{
			string_type result = this->open_block('{');
			BOOST_FOREACH(stmt_ptr stmt, node.statements)
				result += this->indent() + this->apply(*stmt) + O2_CSTR(";\n");
			result += this->close_block();
			return result;
		}
		
		template <class T>
		StringT visit(T) const
			{ return L"xxx"; }
			
		string_type method_name(const string_type& name)
		{
			if (name == O2_CSTR("constructor"))
				return O2_CSTR("__construct");
			if (name == O2_CSTR("destructor"))
				return O2_CSTR("__destruct");
			return name;
		}
		
};

// ----------------------------------------------------------------------------

typedef basic_php_renderer<std::string> php_renderer;
typedef basic_php_renderer<std::wstring> wphp_renderer;

// ----------------------------------------------------------------------------
} // namespace php
} // namespace codegen
} // namespace o2
#endif // O2_CODEGEN_PHP_PHP_VISITOR
// ----------------------------------------------------------------------------
